# -*- coding: utf-8 -*-


"""
伶伦 WXGUI
Linglun Studio WxPython GUI

版权所有 © 2024 金羿ELS & 睿乐开发组
Copyright © 2024 EillesWan & TriM Org.

伶伦WXGUI版本（“本项目”）的协议颁发者为 金羿
The Licensor of _Linglun Studio WxPython GUI_("this project") is Eilles Wan.

本项目根据 第一版 汉钰律许可协议（“本协议”）授权。
任何人皆可从以下地址获得本协议副本：https://gitee.com/EillesWan/YulvLicenses。
若非因法律要求或经过了特殊准许，此作品在根据本协议“原样”提供的基础上，不予提供任何形式的担保、任何明示、任何暗示或类似承诺。也就是说，用户将自行承担因此作品的质量或性能问题而产生的全部风险。
详细的准许和限制条款请见原协议文本。
"""


# 伶伦 开发交流群 861684859
# Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库根目录下的 License.md


# BUG退散！BUG退散！                  BUG退散！BUG退散！                   BUG retreat! BUG retreat!
# 异常与错误作乱之时                   異常、誤りが、困った時は               Abnormalities and errors are causing chaos
# 二六字组！万国码合！二六字组！万国码合！ グループ！コード＃！グループ！コード＃！  Words combine! Unicode unite!
# 赶快呼叫 程序员！Let's Go！          直ぐに呼びましょプログラマ レッツゴー！  Hurry to call the programmer! Let's Go!


# 下面为正文

# 音·创 为梦而创，为爱远航

from dataclasses import dataclass
import os
import random

import wx

# import wx.xrc
import wx.propgrid as pg

import Musicreater.experiment
from utils.io import logger, object_constants, log__init__, TrimLog
from utils.yanlun import yanlun_go, yanlun_fg_colour, yanlun_bg_colour
from utils.settings import WHITE, BLACK


from utils.packdata import enpack_lls_pack, unpack_lls_pack, load_msct_packed_data


import Musicreater


__appname__ = "伶伦"
__version__ = "WXGUI 0.0.0"
__zhver__ = "WX图形界面 预版"


osc = object_constants.ObjectStateConstant(
    logging_project_name=__appname__,
    logging_project_version=__version__,
    logging_exit_exec=lambda sth: wx.MessageDialog(
        None,
        sth + "\n问题不大吧？有问题拜托请报给开发者！谢谢！",
        "崩溃",
        wx.YES_DEFAULT | wx.ICON_STOP,
    ).ShowModal(),
    # is_this_a_release=True,
)
# print(osc.exit_execution)
osc.set_console(logger.console)

log__init__(osc, TrimLog.PipManage(True, True, 40), True)

logger.is_logging = True
logger.suffix = ".lls"
logger.is_tips = True
logger.printing = not osc.is_release


yanlun_length = len(yanlun_go)


logger.info("注册“量”并读取内容……")

on_exit_saving = True


MAX_LENGTH = 2200

# Define grid cell dimensions
GRID_WIDTH = 3
GRID_HEIGHT = 10

# Define snap and border thresholds
SNAP_THRESHOLD = 5
BORDER_THRESHOLD = 3


@dataclass
class Rectangle:

    x_pos: int
    y_pos: int
    width_length: int
    colour: wx.Colour
    note: Musicreater.MineNote

    def __init__(self, x, y, width, colour: tuple, note_: Musicreater.MineNote):
        self.x_pos = x * GRID_WIDTH
        self.y_pos = y * GRID_HEIGHT
        self.width_length = width * GRID_WIDTH
        self.colour = wx.Colour(colour)
        self.note = note_

    @classmethod
    def from_note(cls, note: Musicreater.MineNote, colour: tuple):
        return cls(note.start_tick, note.note_pitch, note.duration, colour, note)

    @property
    def x(self):
        return round(self.x_pos / GRID_WIDTH)

    @property
    def y(self):
        return round(self.y_pos / GRID_HEIGHT)

    @property
    def width(self):
        return round(self.width_length / GRID_WIDTH)

    @property
    def pos(self):
        return wx.Point(round(self.x_pos), round(self.y_pos))

    def redefine_pos(self, pos: wx.Point):
        self.x_pos = pos.x
        self.y_pos = pos.y


# 创建应用程序类
class LinglunStudioApp(wx.App):
    def OnInit(self):
        # 创建主窗口
        self.SetAppName(__appname__)
        self.frame = LingLunMainFrame(
            None,
        )
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True


logger.info("加载窗口布局……")


class LingLunMainFrame(wx.Frame):

    def __init__(self, parent):
        wx.Frame.__init__(
            self,
            parent,
            id=wx.ID_ANY,
            title=wx.EmptyString,
            pos=wx.DefaultPosition,
            size=wx.Size(1200, 720),
            style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL,
        )

        self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)
        self.SetFont(
            wx.Font(
                wx.NORMAL_FONT.GetPointSize(),
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                "OPPOSans R",
            )
        )
        self.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT))
        self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW))

        self.m_statusBar2 = self.CreateStatusBar(1, wx.STB_SIZEGRIP, wx.ID_ANY)
        self.m_statusBar2.SetFont(
            wx.Font(
                wx.NORMAL_FONT.GetPointSize(),
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                "OPPOSans R",
            )
        )

        self.m_menubar1 = wx.MenuBar(0)
        self.m_menubar1.SetFont(
            wx.Font(
                wx.NORMAL_FONT.GetPointSize(),
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                "OPPOSans R",
            )
        )

        self.FileMenu = wx.Menu()
        self.m_SaveProj_menuItem9 = wx.MenuItem(
            self.FileMenu, wx.ID_ANY, "保存", wx.EmptyString, wx.ITEM_NORMAL
        )
        self.FileMenu.Append(self.m_SaveProj_menuItem9)

        self.FileMenu.AppendSeparator()

        self.m_Import_submenu1 = wx.Menu()
        self.m_ImportFromMidi_menuItem10 = wx.MenuItem(
            self.m_Import_submenu1,
            wx.ID_ANY,
            "从Midi文件导入",
            wx.EmptyString,
            wx.ITEM_NORMAL,
        )
        self.m_Import_submenu1.Append(self.m_ImportFromMidi_menuItem10)

        self.FileMenu.AppendSubMenu(self.m_Import_submenu1, "导入…")

        self.FileMenu.AppendSeparator()

        self.m_ClearSetting_menuItem2 = wx.MenuItem(
            self.FileMenu,
            wx.ID_ANY,
            "重置设置",
            "将全部数据设置重置为默认值（下次启动时生效）",
            wx.ITEM_CHECK,
        )
        self.FileMenu.Append(self.m_ClearSetting_menuItem2)

        self.m_Exit_menuItem1 = wx.MenuItem(
            self.FileMenu, wx.ID_ANY, "退出", "这是退出按钮", wx.ITEM_NORMAL
        )
        self.FileMenu.Append(self.m_Exit_menuItem1)

        self.m_menubar1.Append(self.FileMenu, "文件")

        self.AdoptMenu = wx.Menu()
        self.play_via_websocket = wx.MenuItem(
            self.AdoptMenu,
            wx.ID_ANY,
            "启用WebSocket服务播放",
            "在指定端口上开启WebSocket播放服务器",
            wx.ITEM_NORMAL,
        )
        self.AdoptMenu.Append(self.play_via_websocket)

        self.m_Export_menuItem11 = wx.MenuItem(
            self.AdoptMenu, wx.ID_ANY, "导出…", wx.EmptyString, wx.ITEM_NORMAL
        )
        self.AdoptMenu.Append(self.m_Export_menuItem11)

        self.m_menubar1.Append(self.AdoptMenu, "接出")

        self.AboutMenu = wx.Menu()
        self.m_author_info_menuItem4 = wx.MenuItem(
            self.AboutMenu, wx.ID_ANY, "作者信息", "查看关于信息", wx.ITEM_NORMAL
        )
        self.AboutMenu.Append(self.m_author_info_menuItem4)

        self.m_menubar1.Append(self.AboutMenu, "关于")

        self.SetMenuBar(self.m_menubar1)

        m_mainBoxSizer = wx.BoxSizer(wx.VERTICAL)

        s_yanLunbarSizer = wx.StaticBoxSizer(
            wx.StaticBox(self, wx.ID_ANY, "言·论"), wx.VERTICAL
        )

        self.yanlun_now = random.randrange(0, yanlun_length)
        self.m_LinglunWords_staticText1 = wx.StaticText(
            s_yanLunbarSizer.GetStaticBox(),
            wx.ID_ANY,
            "灵光焕发 深艺献心",
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.ALIGN_CENTER_HORIZONTAL | wx.ST_ELLIPSIZE_MIDDLE | wx.ST_NO_AUTORESIZE,
        )
        self.m_LinglunWords_staticText1.Wrap(-1)

        self.m_LinglunWords_staticText1.SetFont(
            wx.Font(
                12,
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                "OPPOSans B",
            )
        )
        self.m_LinglunWords_staticText1.SetForegroundColour(
            wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
        )
        self.m_LinglunWords_staticText1.SetBackgroundColour(
            wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)
        )

        s_yanLunbarSizer.Add(self.m_LinglunWords_staticText1, 0, wx.EXPAND, 5)

        m_mainBoxSizer.Add(
            s_yanLunbarSizer,
            0,
            wx.ALL | wx.EXPAND | wx.RESERVE_SPACE_EVEN_IF_HIDDEN | wx.TOP,
            2,
        )

        b_MainDCAreaSizer = wx.BoxSizer(wx.HORIZONTAL)

        s_TrackSizer = wx.StaticBoxSizer(
            wx.StaticBox(self, wx.ID_ANY, "乐器注轨"), wx.VERTICAL
        )

        b_MainDCAreaSizer.Add(s_TrackSizer, 5, wx.EXPAND, 5)

        s_NotesSizer = wx.StaticBoxSizer(
            wx.StaticBox(self, wx.ID_ANY, "编辑音符"), wx.VERTICAL
        )

        self.note_pannel = RectanglePanel(self, [])

        s_NotesSizer.Add(self.note_pannel, 1, wx.EXPAND, 5)

        b_MainDCAreaSizer.Add(s_NotesSizer, 40, wx.EXPAND, 5)

        m_mainBoxSizer.Add(b_MainDCAreaSizer, 1, wx.EXPAND, 5)

        self.SetSizer(m_mainBoxSizer)
        self.Layout()

        self.Centre(wx.BOTH)

        # Connect Events
        self.Bind(
            wx.EVT_MENU,
            self.onSaveProjButtonPressed,
            id=self.m_SaveProj_menuItem9.GetId(),
        )
        self.Bind(
            wx.EVT_MENU,
            self.onImportFromMidiButtonPressed,
            id=self.m_ImportFromMidi_menuItem10.GetId(),
        )
        self.Bind(
            wx.EVT_MENU,
            self.onResetSettingButtonSelection,
            id=self.m_ClearSetting_menuItem2.GetId(),
        )
        self.Bind(
            wx.EVT_MENU, self.onExitButtonPressed, id=self.m_Exit_menuItem1.GetId()
        )
        self.Bind(
            wx.EVT_MENU,
            self.onWebSocketPlayButtonPressed,
            id=self.play_via_websocket.GetId(),
        )
        self.Bind(
            wx.EVT_MENU, self.onExportButtonPressed, id=self.m_Export_menuItem11.GetId()
        )
        self.Bind(
            wx.EVT_MENU,
            self.on_author_button_pressed,
            id=self.m_author_info_menuItem4.GetId(),
        )
        self.m_LinglunWords_staticText1.Bind(
            wx.EVT_LEFT_DCLICK, self.onYanlunDoubleClicked
        )
        self.m_LinglunWords_staticText1.Bind(wx.EVT_MOUSEWHEEL, self.onYanlunWheeled)

    def __del__(self):
        pass

    # Virtual event handlers, override them in your derived class
    def onSaveProjButtonPressed(self, event):
        event.Skip()

    def onImportFromMidiButtonPressed(self, event):
        self.OpenMidiFrame = CheckerFrame4OpenMidi(self)
        self.OpenMidiFrame.Show()
        self.OpenMidiFrame.Bind(wx.EVT_WINDOW_DESTROY, self.onOpenMidiFrameClosed)
        event.Skip()

    def onOpenMidiFrameClosed(self, event):
        self.msq = self.OpenMidiFrame.MsSq
        # print(self.msq)
        self.colour_map = dict(
            [
                (
                    nns,
                    (
                        random.randint(0, 255),
                        random.randint(0, 255),
                        random.randint(0, 255),
                    ),
                )
                for nns in self.msq.note_count_per_instrument.keys()
            ]
        )
        self.note_pannel.set_rectangles(
            [
                Rectangle.from_note(note, (self.colour_map[note.sound_name]))
                for note in sorted(
                    [i for j in self.msq.channels.values() for i in j],
                    key=lambda note: note.start_tick,
                )
            ]
        )
        # self.note_pannel.on_paint(None)
        self.note_pannel.Refresh()
        event.Skip()

    def onResetSettingButtonSelection(self, event):
        global on_exit_saving
        if self.m_ClearSetting_menuItem2.IsChecked():
            on_exit_saving = False
        else:
            on_exit_saving = True

    def onExitButtonPressed(self, event):
        self.Destroy()

    def onWebSocketPlayButtonPressed(self, event):
        event.Skip()

    def onExportButtonPressed(self, event):
        event.Skip()

    def on_author_button_pressed(self, event):
        pass

    def onYanlunDoubleClicked(self, event):
        self.yanlun_now = random.randrange(0, yanlun_length)
        self.m_LinglunWords_staticText1.SetLabelText(
            yanlun_go[self.yanlun_now] + "\r"
        )

    def onYanlunWheeled(self, event):
        if event.GetWheelRotation() < 0:
            self.yanlun_now += 1
        else:
            self.yanlun_now -= 1
        self.yanlun_now += (
            -yanlun_length
            if self.yanlun_now >= yanlun_length
            else (yanlun_length if self.yanlun_now < 0 else 0)
        )
        self.m_LinglunWords_staticText1.SetLabelText(
            yanlun_go[self.yanlun_now] + "\r"
        )


class RectanglePanel(wx.ScrolledWindow):
    def __init__(self, parent, rectangles: list):
        super().__init__(parent, size=(600, 600))

        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
        self.Bind(wx.EVT_PAINT, self.on_paint)
        self.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
        self.Bind(wx.EVT_LEFT_UP, self.on_left_up)
        self.Bind(wx.EVT_MOTION, self.on_mouse_move)
        self.Bind(wx.EVT_MOUSEWHEEL, self.on_mouse_wheel)

        self.rect_height = GRID_HEIGHT
        self.rectangles = rectangles
        self.dragging = False
        self.resizing = False
        self.offset = wx.Point(0, 0)
        self.selected_rectangle = None
        self.zoom_factor = 1.0

        self.SetScrollRate(GRID_WIDTH, GRID_HEIGHT)
        self.SetVirtualSize((MAX_LENGTH * GRID_WIDTH, GRID_HEIGHT * 128))

    def set_rectangles(self, rectangles: list):
        self.rectangles = rectangles

    def get_cursor_pos(self, event) -> tuple:
        scrolled_x = self.GetScrollPos(wx.HORIZONTAL)
        scrolled_y = self.GetScrollPos(wx.VERTICAL)

        pos = event.GetPosition()

        return (
            pos.x / self.zoom_factor + scrolled_x * GRID_WIDTH,
            pos.y / self.zoom_factor + scrolled_y * GRID_HEIGHT,
        )

    def on_paint(self, event):
        dc = wx.AutoBufferedPaintDC(self)
        self.PrepareDC(dc)
        dc.Clear()
        self.draw_grid(dc)
        self.draw_line_numbers(dc)
        self.draw_column_numbers(dc)
        self.draw_rectangles(dc)

        # scroll_x = self.GetScrollPos(wx.HORIZONTAL)
        # scroll_y = self.GetScrollPos(wx.VERTICAL)

        # print(f"Horizontal Scroll Position: {scroll_x}")
        # print(f"Vertical Scroll Position: {scroll_y}")

    def draw_grid(self, dc):
        dc.SetPen(wx.Pen(wx.Colour(200, 200, 200), 1, wx.PENSTYLE_SOLID))
        width, height = self.GetVirtualSize()
        for x in range(0, round(width / self.zoom_factor + 0.5), GRID_WIDTH):
            dc.DrawLine(int(x * self.zoom_factor), 0, int(x * self.zoom_factor), height)
        for y in range(0, round(height / self.zoom_factor + 0.5), GRID_HEIGHT):
            dc.DrawLine(0, int(y * self.zoom_factor), width, int(y * self.zoom_factor))

    def draw_rectangles(self, dc):
        for rect in self.rectangles:
            dc.SetBrush(wx.Brush(rect.colour))
            dc.SetPen(
                wx.Pen(
                    rect.colour, width=round(self.zoom_factor), style=wx.PENSTYLE_SOLID
                )
            )
            dc.DrawRectangle(
                int(rect.x_pos * self.zoom_factor),
                int(rect.y_pos * self.zoom_factor),
                int(rect.width_length * self.zoom_factor),
                int(self.rect_height * self.zoom_factor),
            )

    def draw_line_numbers(self, dc):
        dc.SetFont(
            wx.Font(
                10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL
            )
        )
        dc.SetTextForeground(wx.Colour(0, 0, 0))
        for i in range(
            0, self.GetVirtualSize()[1] // int(GRID_HEIGHT * self.zoom_factor)
        ):
            dc.DrawText(str(i), 5, round(i * GRID_HEIGHT * self.zoom_factor + 5))

    def draw_column_numbers(self, dc):
        dc.SetFont(
            wx.Font(
                10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL
            )
        )
        dc.SetTextForeground(wx.Colour(0, 0, 0))
        for i in range(
            0, self.GetVirtualSize()[0] // int(GRID_WIDTH * self.zoom_factor)
        ):
            if i % 5 == 0:
                dc.DrawText(str(i), round(i * GRID_WIDTH * self.zoom_factor + 5), 5)

    def on_left_down(self, event):
        pos = self.get_cursor_pos(event)
        for rect in self.rectangles:
            rect_right = rect.x_pos + rect.width_length
            if (
                rect.x_pos <= pos[0] <= rect_right
                and rect.y_pos <= pos[1] <= rect.y_pos + self.rect_height
            ):
                if abs(pos[0] - rect_right) <= BORDER_THRESHOLD:
                    self.resizing = True
                else:
                    self.dragging = True
                    self.offset = wx.Point(
                        round(pos[0] - rect.pos.x),
                        round(pos[1] - rect.pos.y),
                    )
                self.selected_rectangle = rect
                break

    def on_left_up(self, event):
        if self.dragging or self.resizing:
            self.dragging = False
            self.resizing = False
            self.snap_to_grid()
            self.Refresh()
            self.determin_note()

    def on_mouse_move(self, event):
        pos = self.get_cursor_pos(event)
        if event.Dragging() and event.LeftIsDown():
            if self.dragging and self.selected_rectangle:
                self.selected_rectangle.x_pos = pos[0] - self.offset.x
                self.selected_rectangle.y_pos = pos[1] - self.offset.y
                self.apply_snap_effect()
                self.Refresh()
            elif self.resizing and self.selected_rectangle:
                new_width = pos[0] - self.selected_rectangle.x_pos
                if new_width >= GRID_WIDTH:
                    self.selected_rectangle.width_length = new_width
                    snap_w = round(self.selected_rectangle.width) * GRID_WIDTH
                    if (
                        abs(snap_w - self.selected_rectangle.width_length)
                        <= SNAP_THRESHOLD
                    ):
                        self.selected_rectangle.width_length = snap_w
                self.Refresh()
        else:
            cursor = wx.Cursor(wx.CURSOR_ARROW)
            for rect in self.rectangles:
                rect_right = rect.x_pos + rect.width_length
                if (
                    rect.x_pos <= pos[0] <= rect_right
                    and rect.y_pos <= pos[1] <= rect.y_pos + self.rect_height
                ):
                    if abs(pos[0] - rect_right) <= BORDER_THRESHOLD:
                        cursor = wx.Cursor(wx.CURSOR_SIZEWE)
                    else:
                        cursor = wx.Cursor(wx.CURSOR_SIZING)
                    break
            self.SetCursor(cursor)

    def apply_snap_effect(self):
        if not self.selected_rectangle:
            raise ValueError("No rectangle selected")
        snap_x = round(self.selected_rectangle.x * GRID_WIDTH)
        snap_y = round(self.selected_rectangle.y * GRID_HEIGHT)

        dist_x, dist_y = (
            snap_x - self.selected_rectangle.x_pos,
            snap_y - self.selected_rectangle.y_pos,
        )

        if abs(dist_x) <= SNAP_THRESHOLD:
            self.selected_rectangle.x_pos = snap_x
        if abs(dist_y) <= SNAP_THRESHOLD:
            self.selected_rectangle.y_pos = snap_y

    def snap_to_grid(self):
        if not self.selected_rectangle:
            raise ValueError("No rectangle selected")
        snap_x = round(self.selected_rectangle.x) * GRID_WIDTH
        snap_y = round(self.selected_rectangle.y) * GRID_HEIGHT
        self.selected_rectangle.redefine_pos(wx.Point(snap_x, snap_y))

    def determin_note(self):
        if not self.selected_rectangle:
            raise ValueError("No rectangle selected")

        self.selected_rectangle.note.start_tick = self.selected_rectangle.x
        self.selected_rectangle.note.note_pitch = self.selected_rectangle.y
        self.selected_rectangle.note.duration = self.selected_rectangle.width

        print(
            "The rectangle is on pos ({},{}), with width of {}".format(
                self.selected_rectangle.x,
                self.selected_rectangle.y,
                self.selected_rectangle.width,
            )
        )

    def on_mouse_wheel(self, event):
        if event.ControlDown():
            delta = event.GetWheelRotation()
            if delta > 0:
                self.zoom_factor *= 1.1
            elif delta < 0:
                self.zoom_factor /= 1.1

            self.SetScrollRate(
                round(GRID_WIDTH * self.zoom_factor),
                round(GRID_HEIGHT * self.zoom_factor),
            )
            self.SetVirtualSize(
                (
                    round(MAX_LENGTH * GRID_WIDTH * self.zoom_factor + 0.5),
                    round(GRID_HEIGHT * 128 * self.zoom_factor + 0.5),
                )
            )
            self.Refresh()
        elif event.ShiftDown():
            # Handle horizontal scrolling
            scroll_x = self.GetScrollPos(wx.HORIZONTAL)
            delta_x = (
                event.GetWheelRotation() // event.GetWheelDelta()
            )  # * event.GetLinesPerAction()
            self.Scroll(scroll_x - delta_x, -1)
        else:
            # Handle vertical scrolling
            scroll_y = self.GetScrollPos(wx.VERTICAL)
            delta_y = (
                event.GetWheelRotation() // event.GetWheelDelta()
            )  # * event.GetLinesPerAction()
            self.Scroll(-1, scroll_y - delta_y)


class LLMidiImportMainPanel(wx.Panel):

    def __init__(
        self,
        parent,
        id=wx.ID_ANY,
        pos=wx.DefaultPosition,
        size=wx.Size(714, 704),
        style=wx.TAB_TRAVERSAL,
        name=wx.EmptyString,
    ):
        wx.Panel.__init__(
            self, parent, id=id, pos=pos, size=size, style=style, name=name
        )

        self.convert_table_selection = {
            "PITCHED": "“偷吃”的对照表",
            "PERCUSSION": "“偷吃”的对照表",
        }
        self.convert_tables = {
            "PITCHED": {
                "“偷吃”的对照表": Musicreater.MM_TOUCH_PITCHED_INSTRUMENT_TABLE,
                "“经典”对照表": Musicreater.MM_CLASSIC_PITCHED_INSTRUMENT_TABLE,
                "“断联”的对照表": Musicreater.MM_DISLINK_PITCHED_INSTRUMENT_TABLE,
            },
            "PERCUSSION": {
                "“偷吃”的对照表": Musicreater.MM_TOUCH_PERCUSSION_INSTRUMENT_TABLE,
                "“经典”对照表": Musicreater.MM_CLASSIC_PERCUSSION_INSTRUMENT_TABLE,
                "“断联”的对照表": Musicreater.MM_DISLINK_PERCUSSION_INSTRUMENT_TABLE,
            },
        }

        main_page_sizer = wx.BoxSizer(wx.VERTICAL)

        s_MidiBrowseSizer = wx.StaticBoxSizer(
            wx.StaticBox(self, wx.ID_ANY, "选择需要导入的Midi文件"), wx.VERTICAL
        )

        self.m_MidiFilePicker1 = wx.FilePickerCtrl(
            s_MidiBrowseSizer.GetStaticBox(),
            wx.ID_ANY,
            wx.EmptyString,
            "选择需要导入的Midi文件",
            "Midi数字乐谱 (*.mid;*.midi)|*.mid;*.midi",
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.FLP_FILE_MUST_EXIST | wx.FLP_OPEN | wx.FLP_USE_TEXTCTRL,
        )
        s_MidiBrowseSizer.Add(self.m_MidiFilePicker1, 0, wx.ALL | wx.EXPAND, 5)

        main_page_sizer.Add(s_MidiBrowseSizer, 0, wx.EXPAND, 5)

        s_promptSizer = wx.StaticBoxSizer(
            wx.StaticBox(self, wx.ID_ANY, "基本参数"), wx.VERTICAL
        )

        ss_regularPromoptsEnteringSizer1 = wx.BoxSizer(wx.HORIZONTAL)

        sss_VolumnPersentageEnteringSizer = wx.StaticBoxSizer(
            wx.StaticBox(s_promptSizer.GetStaticBox(), wx.ID_ANY, "最小音量"),
            wx.HORIZONTAL,
        )

        self.m_volumn_slider = wx.Slider(
            sss_VolumnPersentageEnteringSizer.GetStaticBox(),
            wx.ID_ANY,
            1000,
            0,
            1000,
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.SL_HORIZONTAL,
        )
        sss_VolumnPersentageEnteringSizer.Add(self.m_volumn_slider, 0, 0, 5)

        self.m_volumn_spinCtrlDouble1 = wx.SpinCtrlDouble(
            sss_VolumnPersentageEnteringSizer.GetStaticBox(),
            wx.ID_ANY,
            "0.1",
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.ALIGN_CENTER_HORIZONTAL | wx.SP_ARROW_KEYS | wx.TE_PROCESS_ENTER,
            0,
            1,
            0.100000,
            0.001,
        )
        self.m_volumn_spinCtrlDouble1.SetDigits(3)
        sss_VolumnPersentageEnteringSizer.Add(self.m_volumn_spinCtrlDouble1, 0, 0, 5)

        ss_regularPromoptsEnteringSizer1.Add(
            sss_VolumnPersentageEnteringSizer, 0, wx.EXPAND | wx.RIGHT, 5
        )

        sss_SpeedEnteringSizer = wx.StaticBoxSizer(
            wx.StaticBox(s_promptSizer.GetStaticBox(), wx.ID_ANY, "播放倍速"),
            wx.HORIZONTAL,
        )

        self.m_speed_slider = wx.Slider(
            sss_SpeedEnteringSizer.GetStaticBox(),
            wx.ID_ANY,
            50,
            0,
            100,
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.SL_HORIZONTAL,
        )
        sss_SpeedEnteringSizer.Add(self.m_speed_slider, 0, 0, 5)

        self.m_speed_spinCtrlDouble = wx.SpinCtrlDouble(
            sss_SpeedEnteringSizer.GetStaticBox(),
            wx.ID_ANY,
            "1",
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.ALIGN_CENTER_HORIZONTAL | wx.SP_ARROW_KEYS | wx.TE_PROCESS_ENTER,
            0.01,
            10,
            1,
            0.1,
        )
        self.m_speed_spinCtrlDouble.SetDigits(2)
        sss_SpeedEnteringSizer.Add(self.m_speed_spinCtrlDouble, 0, 0, 5)

        ss_regularPromoptsEnteringSizer1.Add(
            sss_SpeedEnteringSizer, 0, wx.EXPAND | wx.RIGHT | wx.LEFT, 5
        )

        sss_DeviationEnteringSizer1 = wx.StaticBoxSizer(
            wx.StaticBox(s_promptSizer.GetStaticBox(), wx.ID_ANY, "音调偏移"),
            wx.HORIZONTAL,
        )

        self.m_deviation_slider = wx.Slider(
            sss_DeviationEnteringSizer1.GetStaticBox(),
            wx.ID_ANY,
            0,
            -16000,
            16000,
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.SL_HORIZONTAL,
        )
        sss_DeviationEnteringSizer1.Add(self.m_deviation_slider, 0, 0, 5)

        self.m_deviation_spinCtrlDouble = wx.SpinCtrlDouble(
            sss_DeviationEnteringSizer1.GetStaticBox(),
            wx.ID_ANY,
            "0.0",
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.ALIGN_CENTER_HORIZONTAL | wx.SP_ARROW_KEYS | wx.TE_PROCESS_ENTER,
            -16,
            16,
            0,
            0.001,
        )
        self.m_deviation_spinCtrlDouble.SetDigits(3)
        sss_DeviationEnteringSizer1.Add(self.m_deviation_spinCtrlDouble, 0, 0, 5)

        ss_regularPromoptsEnteringSizer1.Add(
            sss_DeviationEnteringSizer1, 0, wx.EXPAND | wx.LEFT, 5
        )

        s_promptSizer.Add(ss_regularPromoptsEnteringSizer1, 0, wx.EXPAND, 5)

        main_page_sizer.Add(s_promptSizer, 0, wx.SHAPED | wx.EXPAND, 5)

        setting_page_sizer = wx.BoxSizer(wx.VERTICAL)

        self.setting_notebook = wx.Notebook(
            self,
            wx.ID_ANY,
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.NB_FIXEDWIDTH | wx.NB_MULTILINE | wx.NB_RIGHT,
        )
        self.setting_notebook.SetFont(
            wx.Font(
                wx.NORMAL_FONT.GetPointSize(),
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                "@OPPOSans R",
            )
        )
        self.setting_notebook.SetBackgroundColour(
            wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)
        )

        self.setting_page_pitched_inst = wx.Panel(
            self.setting_notebook,
            wx.ID_ANY,
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.TAB_TRAVERSAL,
        )
        self.setting_page_pitched_inst.SetFont(
            wx.Font(
                wx.NORMAL_FONT.GetPointSize(),
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                wx.EmptyString,
            )
        )

        setting_page2_box_sizer = wx.BoxSizer(wx.VERTICAL)

        self.m_pitched_instrument_table_choice = wx.Choice(
            self.setting_page_pitched_inst,
            wx.ID_ANY,
            wx.DefaultPosition,
            wx.DefaultSize,
            list(self.convert_tables["PITCHED"].keys()),
            0,
        )

        self.m_pitched_instrument_table_choice.SetSelection(
            list(self.convert_tables["PITCHED"].keys()).index(
                self.convert_table_selection["PITCHED"]
            )
        )

        self.m_pitched_instrument_table_choice.SetFont(
            wx.Font(
                wx.NORMAL_FONT.GetPointSize(),
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                "OPPOSans R",
            )
        )

        setting_page2_box_sizer.Add(
            self.m_pitched_instrument_table_choice, 0, wx.ALL | wx.EXPAND, 5
        )

        self.m_pitched_notes_table_propertyGrid1 = pg.PropertyGrid(
            self.setting_page_pitched_inst,
            wx.ID_ANY,
            wx.DefaultPosition,
            wx.DefaultSize,
            pg.PG_BOLD_MODIFIED | pg.PG_HIDE_MARGIN | pg.PG_SPLITTER_AUTO_CENTER,
        )
        self.m_pitched_notes_table_propertyGrid1.SetFont(
            wx.Font(
                wx.NORMAL_FONT.GetPointSize(),
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                "OPPOSans R",
            )
        )

        for midi_inst, mc_inst_patern in self.convert_tables["PITCHED"][
            self.convert_table_selection["PITCHED"]
        ].items():
            self.m_pitched_notes_table_propertyGrid1.Append(
                pg.StringProperty(
                    Musicreater.MIDI_PITCHED_NOTE_NAME_TABLE[midi_inst + 1][0],
                    "pitched_inst_{}".format(midi_inst),
                    mc_inst_patern,
                )
            )

        setting_page2_box_sizer.Add(
            self.m_pitched_notes_table_propertyGrid1, 1, wx.ALL | wx.EXPAND, 5
        )

        self.setting_page_pitched_inst.SetSizer(setting_page2_box_sizer)
        self.setting_page_pitched_inst.Layout()
        setting_page2_box_sizer.Fit(self.setting_page_pitched_inst)
        self.setting_notebook.AddPage(
            self.setting_page_pitched_inst, "乐音乐器对照表", True
        )
        self.setting_page_perc_inst = wx.Panel(
            self.setting_notebook,
            wx.ID_ANY,
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.TAB_TRAVERSAL,
        )
        setting_page3_box_sizer = wx.BoxSizer(wx.VERTICAL)

        self.m_percussion_instrument_table_choice1 = wx.Choice(
            self.setting_page_perc_inst,
            wx.ID_ANY,
            wx.DefaultPosition,
            wx.DefaultSize,
            list(self.convert_tables["PERCUSSION"].keys()),
            0,
        )
        self.m_percussion_instrument_table_choice1.SetSelection(
            list(self.convert_tables["PERCUSSION"].keys()).index(
                self.convert_table_selection["PERCUSSION"]
            )
        )
        self.m_percussion_instrument_table_choice1.SetFont(
            wx.Font(
                wx.NORMAL_FONT.GetPointSize(),
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                "OPPOSans R",
            )
        )

        setting_page3_box_sizer.Add(
            self.m_percussion_instrument_table_choice1, 0, wx.ALL | wx.EXPAND, 5
        )

        self.m_percussion_notes_table_propertyGrid11 = pg.PropertyGrid(
            self.setting_page_perc_inst,
            wx.ID_ANY,
            wx.DefaultPosition,
            wx.DefaultSize,
            pg.PG_BOLD_MODIFIED | pg.PG_HIDE_MARGIN | pg.PG_SPLITTER_AUTO_CENTER,
        )
        self.m_percussion_notes_table_propertyGrid11.SetFont(
            wx.Font(
                wx.NORMAL_FONT.GetPointSize(),
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                "OPPOSans R",
            )
        )

        for midi_inst, mc_inst_patern in self.convert_tables["PERCUSSION"][
            self.convert_table_selection["PERCUSSION"]
        ].items():
            self.m_percussion_notes_table_propertyGrid11.Append(
                pg.StringProperty(
                    Musicreater.MIDI_PERCUSSION_NOTE_NAME_TABLE[midi_inst + 1][0],
                    "percussion_inst_{}".format(midi_inst),
                    mc_inst_patern,
                )
            )

        setting_page3_box_sizer.Add(
            self.m_percussion_notes_table_propertyGrid11, 1, wx.ALL | wx.EXPAND, 5
        )

        self.setting_page_perc_inst.SetSizer(setting_page3_box_sizer)
        self.setting_page_perc_inst.Layout()
        setting_page3_box_sizer.Fit(self.setting_page_perc_inst)
        self.setting_notebook.AddPage(
            self.setting_page_perc_inst, "打击乐器对照表", False
        )
        self.setting_page_advanced = wx.Panel(
            self.setting_notebook,
            wx.ID_ANY,
            wx.DefaultPosition,
            wx.DefaultSize,
            wx.TAB_TRAVERSAL,
        )
        self.setting_page_advanced.SetFont(
            wx.Font(
                wx.NORMAL_FONT.GetPointSize(),
                wx.FONTFAMILY_DEFAULT,
                wx.FONTSTYLE_NORMAL,
                wx.FONTWEIGHT_NORMAL,
                False,
                "OPPOSans R",
            )
        )

        setting_page1_box_sizer = wx.BoxSizer(wx.VERTICAL)

        ss_distancefuncChooseSizer = wx.StaticBoxSizer(
            wx.StaticBox(self.setting_page_advanced, wx.ID_ANY, "选择音距处理曲线"),
            wx.VERTICAL,
        )

        self.m_distancefuncChoice_choice_Choices = {
            "自然拟合线": Musicreater.natural_curve,
            "线性直线": Musicreater.straight_line,
        }
        self.m_distancefuncChoice_choice = wx.Choice(
            ss_distancefuncChooseSizer.GetStaticBox(),
            wx.ID_ANY,
            wx.DefaultPosition,
            wx.DefaultSize,
            list(self.m_distancefuncChoice_choice_Choices.keys()),
            0,
        )
        self.m_distancefuncChoice_choice.SetSelection(0)
        ss_distancefuncChooseSizer.Add(
            self.m_distancefuncChoice_choice, 0, wx.ALL | wx.EXPAND, 5
        )

        setting_page1_box_sizer.Add(
            ss_distancefuncChooseSizer, 0, wx.ALL | wx.EXPAND, 5
        )

        setting_page1_experiment_style = wx.StaticBoxSizer(
            wx.StaticBox(self.setting_page_advanced, wx.ID_ANY, "实验性转换功能"),
            wx.HORIZONTAL,
        )

        self.m_enable_experiment_checkBox = wx.CheckBox(
            setting_page1_experiment_style.GetStaticBox(),
            wx.ID_ANY,
            "启用实验性功能",
            wx.DefaultPosition,
            wx.DefaultSize,
            0,
        )
        setting_page1_experiment_style.Add(
            self.m_enable_experiment_checkBox, 1, wx.ALL | wx.EXPAND, 5
        )

        self.experiment_type_choiceChoices: Musicreater.Dict[str, Musicreater.MusicSequence] = {  # type: ignore
            "常规转换": Musicreater.MusicSequence,
            "长音插值": Musicreater.experiment.FutureMidiConvertM4,
            "同刻偏移": Musicreater.experiment.FutureMidiConvertM5,
        }
        self.experiment_type_choice = wx.Choice(
            setting_page1_experiment_style.GetStaticBox(),
            wx.ID_ANY,
            wx.DefaultPosition,
            wx.DefaultSize,
            list(self.experiment_type_choiceChoices.keys()),
            0,
        )
        self.experiment_type_choice.SetSelection(0)
        setting_page1_experiment_style.Add(
            self.experiment_type_choice, 2, wx.ALL | wx.EXPAND, 5
        )

        self.m_ignore_midi_error_checkBox = wx.CheckBox(
            setting_page1_experiment_style.GetStaticBox(),
            wx.ID_ANY,
            "忽略MIDI错误",
            wx.DefaultPosition,
            wx.DefaultSize,
            0,
        )
        self.m_ignore_midi_error_checkBox.SetValue(True)
        setting_page1_experiment_style.Add(
            self.m_ignore_midi_error_checkBox, 1, wx.ALL, 5
        )

        setting_page1_box_sizer.Add(
            setting_page1_experiment_style, 0, wx.ALL | wx.EXPAND, 5
        )

        self.setting_page_advanced.SetSizer(setting_page1_box_sizer)
        self.setting_page_advanced.Layout()
        setting_page1_box_sizer.Fit(self.setting_page_advanced)
        self.setting_notebook.AddPage(self.setting_page_advanced, "高级设置", False)

        setting_page_sizer.Add(self.setting_notebook, 1, wx.EXPAND | wx.ALL, 5)

        main_page_sizer.Add(setting_page_sizer, 8, wx.EXPAND, 5)

        self.SetSizer(main_page_sizer)
        self.Layout()

        # Connect Events
        self.m_volumn_slider.Bind(wx.EVT_SCROLL, self.onVolumeScrolling)
        self.m_volumn_spinCtrlDouble1.Bind(
            wx.EVT_SPINCTRLDOUBLE, self.onVolumeSpinChanged
        )
        self.m_speed_slider.Bind(wx.EVT_SCROLL, self.onSpeedScrolling)
        self.m_speed_spinCtrlDouble.Bind(wx.EVT_SPINCTRLDOUBLE, self.onSpeedSpinChanged)
        self.m_deviation_slider.Bind(wx.EVT_SCROLL, self.onDeviationScrolling)
        self.m_deviation_spinCtrlDouble.Bind(
            wx.EVT_SPINCTRLDOUBLE, self.onDeviationSpinChanged
        )
        self.m_pitched_instrument_table_choice.Bind(
            wx.EVT_CHOICE, self.onPitchedInstListChanging
        )
        self.m_pitched_notes_table_propertyGrid1.Bind(
            pg.EVT_PG_CHANGED, self.onPitchedInstTableChanged
        )
        self.m_pitched_notes_table_propertyGrid1.Bind(
            pg.EVT_PG_CHANGING, self.onPitchedInstTableChanging
        )
        self.m_percussion_instrument_table_choice1.Bind(
            wx.EVT_CHOICE, self.onPercussionInstListChanging
        )
        self.m_percussion_notes_table_propertyGrid11.Bind(
            pg.EVT_PG_CHANGED, self.onPercussionInstTableChanged
        )
        self.m_percussion_notes_table_propertyGrid11.Bind(
            pg.EVT_PG_CHANGING, self.onPercussionInstTableChanging
        )
        self.m_distancefuncChoice_choice.Bind(wx.EVT_CHOICE, self.onDistanceFuncChosen)
        self.m_enable_experiment_checkBox.Bind(
            wx.EVT_CHECKBOX, self.onExperimentEnableUpdating
        )
        self.experiment_type_choice.Bind(wx.EVT_CHOICE, self.onConvertMethodUpdating)
        self.m_ignore_midi_error_checkBox.Bind(
            wx.EVT_CHECKBOX, self.onMidiFaultIgnoranceChecking
        )

    def __del__(self):
        pass

    # Virtual event handlers, override them in your derived class
    def onVolumeScrolling(self, event):
        # prt(self.m_volumn_slider.Value)
        self.m_volumn_spinCtrlDouble1.SetValue(self.m_volumn_slider.Value / 1000)

    def onVolumeSpinChanged(self, event):
        # prt(self.m_volumn_spinCtrlDouble1.Value)
        self.m_volumn_slider.SetValue(int(self.m_volumn_spinCtrlDouble1.Value * 1000))

    def onSpeedScrolling(self, event):
        # prt(self.m_speed_slider.Value)
        if self.m_speed_slider.Value > 50:
            self.m_speed_spinCtrlDouble.SetValue(
                (self.m_speed_slider.Value * 9 - 400) / 50
            )
        else:
            self.m_speed_spinCtrlDouble.SetValue(
                (self.m_speed_slider.Value * 99 + 50) / 5000
            )

    def onSpeedSpinChanged(self, event):
        if self.m_speed_spinCtrlDouble.Value > 1:
            self.m_speed_slider.SetValue(
                int((self.m_speed_spinCtrlDouble.Value + 8) * 50 / 9)
            )
        else:
            self.m_speed_slider.SetValue(
                int((self.m_speed_spinCtrlDouble.Value - 0.01) * 5000 / 99)
            )

    def onDeviationScrolling(self, event):
        self.m_deviation_spinCtrlDouble.SetValue(self.m_volumn_slider.Value / 1000)

    def onDeviationSpinChanged(self, event):
        self.m_deviation_slider.SetValue(
            int(self.m_deviation_spinCtrlDouble.Value * 1000)
        )

    def onPitchedInstListChanging(self, event):
        self.convert_table_selection["PITCHED"] = (
            self.m_pitched_instrument_table_choice.GetStringSelection()
        )
        self.m_pitched_notes_table_propertyGrid1.SetPropertyValues(
            dict(
                [
                    ("pitched_inst_{}".format(midi_inst), mc_inst_patern)
                    for midi_inst, mc_inst_patern in self.convert_tables["PITCHED"][
                        self.convert_table_selection["PITCHED"]
                    ].items()
                ]
            )
        )

        event.Skip()

    def onPitchedInstTableChanged(self, event):
        self.convert_tables["PITCHED"]["自定义对照表"] = dict(
            [
                (i, j)
                for i, j in self.convert_tables["PITCHED"][
                    self.convert_table_selection["PITCHED"]
                ].items()
            ]
        )
        self.convert_table_selection["PITCHED"] = "自定义对照表"
        to_change_id = int(event.GetProperty().GetName().split("_")[-1])
        to_change_value = (
            event.GetProperty().GetValue()
            # Musicreater.MM_INSTRUMENT_DEVIATION_TABLE.get(
            #     event.GetProperty().GetValue(), -1
            # ),
        )
        self.convert_tables["PITCHED"]["自定义对照表"][to_change_id] = to_change_value
        logger.info(
            "自定义乐音乐器对照表第 {} 项已更新为：{}".format(
                to_change_id, to_change_value
            )
        )
        if "自定义对照表" not in self.m_pitched_instrument_table_choice.Items:
            self.m_pitched_instrument_table_choice.Append("自定义对照表")
            self.m_pitched_instrument_table_choice.SetSelection(2)
        event.Skip()

    def onPitchedInstTableChanging(self, event):
        event.Skip()

    def onPercussionInstListChanging(self, event):
        self.convert_table_selection["PERCUSSION"] = (
            self.m_percussion_instrument_table_choice1.GetStringSelection()
        )
        self.m_percussion_notes_table_propertyGrid11.SetPropertyValues(
            dict(
                [
                    ("percussion_inst_{}".format(midi_inst), mc_inst_patern)
                    for midi_inst, mc_inst_patern in self.convert_tables["PERCUSSION"][
                        self.convert_table_selection["PERCUSSION"]
                    ].items()
                ]
            )
        )
        event.Skip()

    def onPercussionInstTableChanged(self, event):
        self.convert_tables["PERCUSSION"]["自定义对照表"] = dict(
            [
                (i, j)
                for i, j in self.convert_tables["PERCUSSION"][
                    self.convert_table_selection["PERCUSSION"]
                ].items()
            ]
        )
        self.convert_table_selection["PERCUSSION"] = "自定义对照表"
        to_change_id = int(event.GetProperty().GetName().split("_")[-1])
        to_change_value = (
            event.GetProperty().GetValue()
            # Musicreater.MM_INSTRUMENT_DEVIATION_TABLE.get(
            #     event.GetProperty().GetValue(), -1
            # ),
        )
        self.convert_tables["PERCUSSION"]["自定义对照表"][
            to_change_id
        ] = to_change_value
        logger.info(
            "自定义打击乐器对照表第 {} 项已更新为：{}".format(
                to_change_id, to_change_value
            )
        )
        if "自定义对照表" not in self.m_percussion_instrument_table_choice1.Items:
            self.m_percussion_instrument_table_choice1.Append("自定义对照表")
            self.m_percussion_instrument_table_choice1.SetSelection(2)
        event.Skip()

    def onPercussionInstTableChanging(self, event):
        event.Skip()

    def onDistanceFuncChosen(self, event):
        event.Skip()

    def onExperimentEnableUpdating(self, event):
        if self.m_enable_experiment_checkBox.GetValue():
            self.m_ignore_midi_error_checkBox.Enable(True)
            self.experiment_type_choice.Enable(True)
        else:
            self.m_ignore_midi_error_checkBox.Enable(False)
            self.experiment_type_choice.Enable(False)
        event.Skip()

    def onConvertMethodUpdating(self, event):
        #  0  "常规转换",  1 "长音插值",  2 "同刻偏移"
        # match self.experiment_type_choice.GetSelection():
        event.Skip()

    def onMidiFaultIgnoranceChecking(self, event):
        event.Skip()


class CheckerFrame4OpenMidi(wx.Frame):

    def __init__(self, parent):
        wx.Frame.__init__(
            self,
            parent,
            id=wx.ID_ANY,
            title="确认",
            pos=wx.DefaultPosition,
            size=wx.Size(750, 860),
            style=wx.CAPTION
            | wx.CLOSE_BOX
            | wx.MINIMIZE_BOX
            | wx.SYSTEM_MENU
            | wx.TAB_TRAVERSAL,
        )

        self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)

        mainSizer1 = wx.BoxSizer(wx.VERTICAL)

        self.m_panel2 = LLMidiImportMainPanel(self)

        mainSizer1.Add(self.m_panel2, 8, wx.EXPAND | wx.ALL, 5)

        m_check_sdbSizer1 = wx.StdDialogButtonSizer()
        self.m_check_sdbSizer1OK = wx.Button(self, wx.ID_OK)
        m_check_sdbSizer1.AddButton(self.m_check_sdbSizer1OK)
        self.m_check_sdbSizer1Cancel = wx.Button(self, wx.ID_CANCEL)
        m_check_sdbSizer1.AddButton(self.m_check_sdbSizer1Cancel)
        m_check_sdbSizer1.Realize()

        mainSizer1.Add(m_check_sdbSizer1, 1, wx.EXPAND, 5)

        self.SetSizer(mainSizer1)
        self.Layout()

        self.Centre(wx.BOTH)

        # Connect Events
        self.m_check_sdbSizer1Cancel.Bind(wx.EVT_BUTTON, self.onCancelPressed)
        self.m_check_sdbSizer1OK.Bind(wx.EVT_BUTTON, self.onOKpressed)

    def __del__(self):
        pass

    # Virtual event handlers, override them in your derived class
    def onCancelPressed(self, event):
        self.MsSq = Musicreater.MusicSequence(
            "",
            dict(),
        )
        self.Destroy()
        event.Skip()

    def onOKpressed(self, event):
        # self.m_panel2.m_MidiFilePicker1.GetTextCtrl().GetValue()
        self.MsSq = list(self.m_panel2.experiment_type_choiceChoices.values())[
            self.m_panel2.experiment_type_choice.GetSelection()
        ].from_mido(
            mido_file=Musicreater.mido.MidiFile(
                self.m_panel2.m_MidiFilePicker1.GetTextCtrl().GetValue()
            ),
            midi_music_name=os.path.splitext(
                os.path.basename(
                    self.m_panel2.m_MidiFilePicker1.GetTextCtrl().GetValue()
                )
            )[0].replace(" ", "_"),
            mismatch_error_ignorance=self.m_panel2.m_ignore_midi_error_checkBox.GetValue(),
            speed_multiplier=self.m_panel2.m_speed_spinCtrlDouble.GetValue(),
            pitched_note_referance_table=self.m_panel2.convert_tables["PITCHED"][
                self.m_panel2.convert_table_selection["PITCHED"]
            ],
            percussion_note_referance_table=self.m_panel2.convert_tables["PERCUSSION"][
                self.m_panel2.convert_table_selection["PERCUSSION"]
            ],
            minimum_vol=self.m_panel2.m_volumn_spinCtrlDouble1.GetValue(),
            volume_processing_function=list(
                self.m_panel2.m_distancefuncChoice_choice_Choices.values()
            )[self.m_panel2.m_distancefuncChoice_choice.GetSelection()],
        )
        self.Destroy()
        event.Skip()


logger.info("执行应用。")

# 启动应用程序
if __name__ == "__main__":

    logger.info("开启窗口")

    app = LinglunStudioApp()

    app.MainLoop()

    if on_exit_saving:
        pass
    else:
        for path, dir_list, file_list in os.walk(r"./"):
            for file_name in file_list:
                if file_name.endswith(".lls.config"):
                    os.remove(
                        os.path.join(path, file_name),
                    )
    # input("按下回车退出……")
